"""Share service for conversations."""

from typing import Optional
from datetime import datetime
import motor.motor_asyncio
from bson import ObjectId
import hashlib

from ..models.conversation_model import Conversation, ConversationStatus


class ShareService:
    """Handles conversation sharing functionality."""
    
    def __init__(self, mongodb_client: motor.motor_asyncio.AsyncIOMotorClient):
        """Initialize share service.
        
        Args:
            mongodb_client: MongoDB client instance
        """
        self.mongodb = mongodb_client
        self.db = mongodb_client.ai_writing
        self.conversations = self.db.conversations
    
    async def create_share_link(
        self,
        conversation_id: str,
        user_id: str,
        expires_at: Optional[datetime] = None,
        password: Optional[str] = None
    ) -> Optional[str]:
        """Create a sharing link for conversation.
        
        Args:
            conversation_id: Conversation ID
            user_id: User ID for ownership verification
            expires_at: Optional expiration time
            password: Optional password protection
            
        Returns:
            Share ID if successful, None otherwise
        """
        # Get conversation
        doc = await self.conversations.find_one({
            "_id": ObjectId(conversation_id),
            "user_id": user_id,
            "status": {"$ne": ConversationStatus.DELETED.value}
        })
        
        if not doc:
            return None
        
        conversation = Conversation.from_dict(doc)
        
        # Generate share link
        share_id = conversation.generate_share_link(
            expires_at=expires_at,
            password=self._hash_password(password) if password else None
        )
        
        # Update in database
        result = await self.conversations.update_one(
            {
                "_id": ObjectId(conversation_id),
                "user_id": user_id
            },
            {
                "$set": {
                    "sharing": conversation.sharing.to_dict(),
                    "updated_at": datetime.utcnow()
                }
            }
        )
        
        if result.modified_count > 0:
            return share_id
        
        return None
    
    async def revoke_share_link(
        self,
        conversation_id: str,
        user_id: str
    ) -> bool:
        """Revoke the sharing link for conversation.
        
        Args:
            conversation_id: Conversation ID
            user_id: User ID for ownership verification
            
        Returns:
            True if revoked successfully
        """
        result = await self.conversations.update_one(
            {
                "_id": ObjectId(conversation_id),
                "user_id": user_id
            },
            {
                "$set": {
                    "sharing.is_shared": False,
                    "sharing.share_id": None,
                    "sharing.share_expires_at": None,
                    "sharing.share_password": None,
                    "sharing.share_views": 0,
                    "updated_at": datetime.utcnow()
                }
            }
        )
        
        return result.modified_count > 0
    
    async def get_shared_conversation(
        self,
        share_id: str,
        password: Optional[str] = None
    ) -> Optional[Conversation]:
        """Access a shared conversation.
        
        Args:
            share_id: Share ID
            password: Optional password for protected shares
            
        Returns:
            Conversation if accessible, None otherwise
        """
        # Find conversation by share ID
        doc = await self.conversations.find_one({
            "sharing.share_id": share_id,
            "sharing.is_shared": True,
            "status": {"$ne": ConversationStatus.DELETED.value}
        })
        
        if not doc:
            return None
        
        conversation = Conversation.from_dict(doc)
        
        # Check expiration
        if conversation.sharing.share_expires_at:
            if datetime.utcnow() > conversation.sharing.share_expires_at:
                # Expired - auto-revoke
                await self.conversations.update_one(
                    {"_id": conversation._id},
                    {
                        "$set": {
                            "sharing.is_shared": False,
                            "sharing.share_id": None,
                            "updated_at": datetime.utcnow()
                        }
                    }
                )
                return None
        
        # Check password
        if conversation.sharing.share_password:
            if not password:
                return None
            
            if not self._verify_password(password, conversation.sharing.share_password):
                return None
        
        # Increment view count
        await self.conversations.update_one(
            {"_id": conversation._id},
            {"$inc": {"sharing.share_views": 1}}
        )
        
        # Return conversation (consider removing sensitive data)
        # Clear user_id for privacy
        conversation.user_id = "[hidden]"
        
        return conversation
    
    async def check_share_status(
        self,
        conversation_id: str,
        user_id: str
    ) -> dict:
        """Check the sharing status of a conversation.
        
        Args:
            conversation_id: Conversation ID
            user_id: User ID for ownership verification
            
        Returns:
            Sharing status information
        """
        doc = await self.conversations.find_one(
            {
                "_id": ObjectId(conversation_id),
                "user_id": user_id
            },
            {"sharing": 1}
        )
        
        if not doc:
            return {"is_shared": False}
        
        sharing = doc.get("sharing", {})
        
        # Check if expired
        if sharing.get("share_expires_at"):
            if datetime.utcnow() > sharing["share_expires_at"]:
                sharing["is_expired"] = True
            else:
                sharing["is_expired"] = False
        
        return sharing
    
    def _hash_password(self, password: str) -> str:
        """Hash a password for storage.
        
        Args:
            password: Plain text password
            
        Returns:
            Hashed password
        """
        # Use SHA256 for simple password hashing
        # In production, consider using bcrypt or argon2
        return hashlib.sha256(password.encode()).hexdigest()
    
    def _verify_password(self, plain_password: str, hashed_password: str) -> bool:
        """Verify a password against its hash.
        
        Args:
            plain_password: Plain text password
            hashed_password: Hashed password
            
        Returns:
            True if password matches
        """
        return self._hash_password(plain_password) == hashed_password
    
    async def get_share_statistics(self, user_id: str) -> dict:
        """Get sharing statistics for a user.
        
        Args:
            user_id: User ID
            
        Returns:
            Dictionary with sharing statistics
        """
        pipeline = [
            {
                "$match": {
                    "user_id": user_id,
                    "sharing.is_shared": True
                }
            },
            {
                "$group": {
                    "_id": None,
                    "total_shared": {"$sum": 1},
                    "total_views": {"$sum": "$sharing.share_views"},
                    "has_password": {
                        "$sum": {
                            "$cond": [
                                {"$ne": ["$sharing.share_password", None]},
                                1,
                                0
                            ]
                        }
                    }
                }
            }
        ]
        
        cursor = self.conversations.aggregate(pipeline)
        stats = await cursor.to_list(length=1)
        
        if stats:
            return stats[0]
        
        return {
            "total_shared": 0,
            "total_views": 0,
            "has_password": 0
        }